﻿// 开源小地图/MapSettingsWidget.cs
using Game;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace Game
{
    public class MapSettingsWidget : CanvasWidget
    {
        public MapSettingsWidget(ComponentPlayer componentPlayer)
        {
            this.m_componentPlayer = componentPlayer;
            LoadWidgetContents();
            InitializeMapSizes();
            FindAllControls();
            SetupSliderRange();
            InitializeControls();
            UpdateButtonTexts();
        }

        public override void Update()
        {
            base.Update();
            ProcessUserInteractions();
        }

        private void LoadWidgetContents()
        {
            XElement xelement = ContentManager.Get<XElement>("Widgets/MapSettingsWidget");
            base.LoadContents(this, xelement);
        }

        private void InitializeMapSizes()
        {
            if (MapSettingsWidget.m_mapSizes.Count == 0)
            {
                MapSettingsWidget.m_mapSizes.AddRange(Enumerable.Range(0, 46).Select(i => 100 + i * 20));
            }
        }

        private void FindAllControls()
        {
            var controlFinder = new Dictionary<string, Action<Widget>>
            {
                { "ToggleMapButton", widget => this.m_toggleMapButton = widget as ButtonWidget },
                { "MoveMapButton", widget => this.m_MoveMapButton = widget as ButtonWidget },
                { "ResetSettingsButton", widget => this.m_resetSettingsButton = widget as ButtonWidget },
                { "MapSizeSlider", widget => this.m_mapSizeSlider = widget as SliderWidget },
                { "MapSizeLabel", widget => this.m_mapSizeLabel = widget as LabelWidget },
                { "Settings", widget => this.m_mapSettings = widget as LabelWidget }
            };

            foreach (var finder in controlFinder)
            {
                finder.Value(this.Children.Find<Widget>(finder.Key, true));
            }
        }

        private void SetupSliderRange()
        {
            if (this.m_mapSizeSlider != null)
            {
                this.m_mapSizeSlider.MinValue = 0f;
                this.m_mapSizeSlider.MaxValue = (float)(MapSettingsWidget.m_mapSizes.Count - 1);
            }
        }

        private void ProcessUserInteractions()
        {
            var interactionHandlers = new List<Func<bool>>
            {
                () => HandleButtonInteraction(this.m_toggleMapButton, ToggleMapVisibility),
                () => HandleButtonInteraction(this.m_MoveMapButton, OpenModifyMapLocationWidget),
                () => HandleButtonInteraction(this.m_resetSettingsButton, ResetAllSettings),
                () => HandleSliderInteraction(this.m_mapSizeSlider, UpdateMapSize)
            };

            interactionHandlers.ForEach(handler => handler());
        }

        private bool HandleButtonInteraction(ButtonWidget button, Action action)
        {
            if (button != null && button.IsClicked)
            {
                action();
                return true;
            }
            return false;
        }

        private bool HandleSliderInteraction(SliderWidget slider, Action action)
        {
            if (slider != null && slider.IsSliding)
            {
                action();
                return true;
            }
            return false;
        }

        private void InitializeControls()
        {
            ComponentMap componentMap = this.m_componentPlayer.Entity.FindComponent<ComponentMap>();

            var controlInitializer = new Action<ComponentMap, Action<int>, Action<int>>((map, sizeSetter, visibilitySetter) =>
            {
                if (map != null)
                {
                    int mapSize = map.MapSize;
                    int closestSizeIndex = GetClosestSizeIndex(mapSize);
                    this.m_mapSizeSlider.Value = (float)closestSizeIndex;
                    visibilitySetter(map.IsVisible ? 1 : 0);
                }
                else
                {
                    int closestSizeIndex = GetClosestSizeIndex(DEFAULT_MAP_SIZE);
                    this.m_mapSizeSlider.Value = (float)closestSizeIndex;
                }
            });

            controlInitializer(componentMap,
                size => { },
                visible => this.m_mapVisible = (visible == 1));

            UpdateButtonTexts();
            UpdateMapSizeText(MapSettingsWidget.m_mapSizes[(int)this.m_mapSizeSlider.Value]);
        }

        private void ResetAllSettings()
        {
            int closestSizeIndex = GetClosestSizeIndex(DEFAULT_MAP_SIZE);
            this.m_mapSizeSlider.Value = (float)closestSizeIndex;
            this.m_mapVisible = true;
            ModifyMapLocationWidget.LastSavedPosition = null;

            ComponentMap componentMap = this.m_componentPlayer.Entity.FindComponent<ComponentMap>();
            if (componentMap != null)
            {
                componentMap.MapSize = DEFAULT_MAP_SIZE;
                componentMap.IsVisible = true;
                componentMap.SmallSquare?.Margin = ComponentMap.InitialSquarePosition;
            }

            UpdateButtonTexts();
            UpdateMapSizeText(DEFAULT_MAP_SIZE);
        }

        private void ToggleMapVisibility()
        {
            this.m_mapVisible = !this.m_mapVisible;
            UpdateButtonTexts();

            ComponentMap componentMap = this.m_componentPlayer.Entity.FindComponent<ComponentMap>();
            componentMap?.SetVisibility(this.m_mapVisible);
        }

        private void OpenModifyMapLocationWidget()
        {
            var gui = this.m_componentPlayer.ComponentGui;
            gui.ModalPanelWidget = null;
            gui.ModalPanelWidget = new ModifyMapLocationWidget(this.m_componentPlayer);
        }

        private void UpdateMapSize()
        {
            int sizeIndex = Math.Clamp((int)this.m_mapSizeSlider.Value, 0, MapSettingsWidget.m_mapSizes.Count - 1);
            int size = MapSettingsWidget.m_mapSizes[sizeIndex];
            UpdateMapSizeText(size);

            ComponentMap componentMap = this.m_componentPlayer.Entity.FindComponent<ComponentMap>();
            componentMap?.SetMapSize(size);
        }

        private int GetClosestSizeIndex(int size)
        {
            var sizeDifferences = MapSettingsWidget.m_mapSizes
                .Select((mapSize, index) => new { Difference = Math.Abs(mapSize - size), Index = index })
                .OrderBy(diff => diff.Difference)
                .ThenByDescending(diff => MapSettingsWidget.m_mapSizes[diff.Index])
                .FirstOrDefault();

            return sizeDifferences?.Index ?? 0;
        }

        private void UpdateButtonTexts()
        {
            string language = ModsManager.Configs.GetValueOrDefault("Language", "zh-CN");
            var textUpdater = new LanguageTextUpdater(language);

            textUpdater.UpdateButton(this.m_toggleMapButton,
                this.m_mapVisible ? new[] { "隐藏", "Hide Map" } : new[] { "显示", "Show Map" });

            textUpdater.UpdateButton(this.m_MoveMapButton, new[] { "移动", "Move Map" });
            textUpdater.UpdateButton(this.m_resetSettingsButton, new[] { "重置", "Reset" });
            textUpdater.UpdateLabel(this.m_mapSettings, new[] { "地图设置", "Map Settings" });
        }

        private void UpdateMapSizeText(int size)
        {
            if (this.m_mapSizeLabel != null)
            {
                string language = ModsManager.Configs.GetValueOrDefault("Language", "zh-CN");
                string format = language == "zh-CN" ?
                    $"［地图大小: {size}像素］" :
                    $"［Map Size: {size}px］";
                this.m_mapSizeLabel.Text = format;
            }
        }

        public ComponentPlayer m_componentPlayer;
        public ButtonWidget m_toggleMapButton;
        public ButtonWidget m_MoveMapButton;
        public ButtonWidget m_resetSettingsButton;
        public SliderWidget m_mapSizeSlider;
        public LabelWidget m_mapSizeLabel;
        public LabelWidget m_mapSettings;
        public bool m_mapVisible = true;
        private string fName = "MapSettingsWidget";
        private static List<int> m_mapSizes = new List<int>();
        private const int DEFAULT_MAP_SIZE = 300;

        private class LanguageTextUpdater
        {
            private readonly string language;

            public LanguageTextUpdater(string lang)
            {
                this.language = lang;
            }

            public void UpdateButton(ButtonWidget button, string[] texts)
            {
                if (button != null)
                {
                    button.Text = texts[language == "zh-CN" ? 0 : 1];
                }
            }

            public void UpdateLabel(LabelWidget label, string[] texts)
            {
                if (label != null)
                {
                    label.Text = texts[language == "zh-CN" ? 0 : 1];
                }
            }
        }
    }

    public static class ComponentMapExtensions
    {
        public static void SetVisibility(this ComponentMap componentMap, bool isVisible)
        {
            componentMap.IsVisible = isVisible;
        }

        public static void SetMapSize(this ComponentMap componentMap, int size)
        {
            componentMap.MapSize = size;
        }
    }
}